﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Interop;

namespace FourPartHarmony2
{
    class Glass
    {
        private Window      window;
        private IntPtr      windowHwnd;
        private HwndSource  windowHwndSource;
        private int topY;

        public Glass(Window window, int topY) {
            this.window = window;
            this.topY = topY;

            WindowInteropHelper wih = new WindowInteropHelper(window);
            windowHwnd = wih.Handle;

            windowHwndSource = PresentationSource.FromVisual(window) as HwndSource;
            windowHwndSource.AddHook(new HwndSourceHook(MainWindowHwndMessageFilter));
        }

        private float _DesktopDpiY = 0.0f;
        private float DesktopDpiY {
            get {
                if (windowHwnd != null && _DesktopDpiY <= 0.0f) {
                    System.Drawing.Graphics desktop = System.Drawing.Graphics.FromHwnd(windowHwnd);
                    _DesktopDpiY = desktop.DpiY;
                }

                return _DesktopDpiY;
            }
        }

        private float _DesktopDpiX = 0.0f;
        private float DesktopDpiX {
            get {
                if (windowHwnd != null && _DesktopDpiX <= 0.0f) {
                    System.Drawing.Graphics desktop = System.Drawing.Graphics.FromHwnd(windowHwnd);
                    _DesktopDpiX = desktop.DpiX;
                }

                return _DesktopDpiX;
            }
        }

        class DwmApi
        {
            [DllImport("DwmApi.dll")]
            public static extern int DwmIsCompositionEnabled(
                ref bool fEnabled);
            public const int WM_DWMCOMPOSITIONCHANGED = 0x0000031E;
            public const int DWM_BB_ENABLE            = 0x00000001;
            public const int DWM_BB_BLURREGION        = 0x00000002;

            [StructLayout(LayoutKind.Sequential)]
            public struct DWM_BLURBEHIND
            {
                public int dwFlags;
                public bool fEnable;
                public IntPtr hRgnBlur;
                public bool fTransitionOnMaximized;
            };

            [DllImport("DwmApi.dll")]
            public static extern int DwmEnableBlurBehindWindow(
                IntPtr hwnd,
                ref DWM_BLURBEHIND bb);

            [StructLayout(LayoutKind.Sequential)]
            public struct MARGINS
            {
                public int cxLeftWidth;
                public int cxRightWidth;
                public int cyTopHeight;
                public int cyBottomHeight;
            };

            [DllImport("DwmApi.dll")]
            public static extern int DwmExtendFrameIntoClientArea(
                IntPtr hwnd,
                ref MARGINS m);
        }

        class Win32
        {
            [StructLayout(LayoutKind.Sequential)]
            public struct RECT
            {
                public int left;
                public int top;
                public int right;
                public int bottom;
            };

            [DllImport("user32.dll")]
            public static extern int GetClientRect(
                IntPtr hwnd,
                ref RECT rect);

        }

        IntPtr MainWindowHwndMessageFilter(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
            switch (msg) {
            case DwmApi.WM_DWMCOMPOSITIONCHANGED:
                Apply();
                handled = true;
                break;
            default:
                handled = false;
                break;
            }

            return IntPtr.Zero;
        }

        public void Apply() {
            try {
                bool IsCompositionEnabled = false;

                DwmApi.DwmIsCompositionEnabled(ref IsCompositionEnabled);
                if (IsCompositionEnabled) {
                    window.Background = Brushes.Transparent;

                    Win32.RECT r = new Win32.RECT();
                    Win32.GetClientRect(windowHwnd, ref r);

                    DwmApi.DWM_BLURBEHIND bb = new DwmApi.DWM_BLURBEHIND();
                    bb.dwFlags = DwmApi.DWM_BB_ENABLE | DwmApi.DWM_BB_BLURREGION;
                    bb.fEnable = true;
                    bb.hRgnBlur = IntPtr.Zero;
                    DwmApi.DwmEnableBlurBehindWindow(windowHwnd, ref bb);

                    DwmApi.MARGINS margins = new DwmApi.MARGINS();
                    margins.cxLeftWidth = Convert.ToInt32(5 * (DesktopDpiX / 96));
                    margins.cxRightWidth = Convert.ToInt32(5 * (DesktopDpiX / 96));
                    margins.cyTopHeight = Convert.ToInt32(topY * (DesktopDpiY / 96));
                    margins.cyBottomHeight = Convert.ToInt32(5 * (DesktopDpiY / 96));

                    HwndSource source = HwndSource.FromHwnd(windowHwnd);
                    source.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0);

                    int hr = DwmApi.DwmExtendFrameIntoClientArea(source.Handle, ref margins);
                    if (hr < 0) {
                        throw new ApplicationException("DwmExtendFrameIntoClientArea: Failed with " + hr);
                    }

                } else {
                    window.Background = Brushes.White;
                }
            } catch (ApplicationException) {
                window.Background = Brushes.White;
                throw;
            } catch (DllNotFoundException) {
                window.Background = Brushes.White;
            }
        }
    }
}
